package com.gec.component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import com.gec.exception.ParseException;
import com.gec.exception.ResNotFoundException;

public class RequestTask implements Runnable {
    //{1}这里要设置两个参数
    private WebContainer container;
    private Socket socket;

    //{2}这里要设置一个构造器
    public RequestTask(WebContainer container,
                       Socket socket) {
        this.container = container;
        this.socket = socket;
    }

    //{3}这里要设置 run 方法
    @Override
    public void run() {
        //{1}声明好变量...
        InputStream is = null;
        OutputStream os = null;
        HttpServletRequest request = null;
        HttpServletResponse response = null;

        try {
            //{2}获取 输入 / 输出流。
            is = socket.getInputStream();
            os = socket.getOutputStream();

            //{3}解析协议, 并获取 req 对象(可能为空)
            request = getRequestInfo(is);
            //{4}创建 resp 对象。
            response = new HttpServletResponseWapper(os);

            //--------------------[处理请求]--------------------------
            String resPath = request.getResPath();
            //{5}根据 resPath 去查找 Servlet 对象。
            HttpServlet servlet = container.findServlet(resPath);
            if (servlet != null) {
                //{6}存在去调用 servlet {动态资源}
                container.callServlet(servlet, request, response);
            } else {
                //{6}不存在 servlet 去查找静态资源。
                //   普通资源找不到 ----> ResNotFound 异常
                container.callDefaultServlet(resPath, request, response);
            }

        } catch (IOException | ParseException e) {
            e.printStackTrace();
            //{ps}这里如何处理待定 【可能性较低】
        } catch (ClassNotFoundException
                | InstantiationException
                | IllegalAccessException e) {
            e.printStackTrace();
            //{ps}------------【开发者要注意】
        } catch (ResNotFoundException e) {
            //e.printStackTrace();
            // 输出404错误
            try {
                sene404Error(request, response);
                System.out.println("{RequestTask}找不到这个资源：" + request.getResPath());
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            //{ps}这里如何处理待定 【可能性较高】
        } finally {
            try {
                response.flush();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void sene404Error(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String resPath = req.getResPath();
        String respBody =
                "<!DOCTYPE html>" +
                        "<html>" +
                        "<body>" +
                        "<h1>404，当前资源" + resPath + "不存在</h1>" +
                        "</body>" +
                        "</html>";
        resp.setContentType("text/html;charset=UTF-8");  // 设置编码
        resp.getWriter().write(respBody);

    }

    //{ps}设置参数到 req 对象中      [已完成:10-16 11:30]
    //参数是这样的: username=andy&password=123
    public void setParamsToReq(HttpServletRequest req,
                               String paras) {
        if (paras == null || paras.length() == 0) {
            return;
        }
        String[] data = paras.split("&");
        for (String d : data) {
            String[] p = d.split("=");
            // 防止输入空数据，有参数没有值，会出现下标越界
            if (p.length == 2) {
                req.addParameter(p[0], p[1]);
            }
        }
    }

    //{2}解析请求行
    //请求行: GET /XxServlet?name=andy&pass=123
    //      POST /XxServlet?name=andy
    public void parseRequestLine(String reqLine,
                                 HttpServletRequest req) {
        //{1}分割请求行
        //   [GET /XxServlet] [name=andy&pass=123]
        String[] part = reqLine.split("\\?");

        //{2}解析参数设置到 req.
        //这些参数: name=andy&pass=123
        if (part.length == 2) {
            setParamsToReq(req, part[1]);
        }

        //part[0] = GET /XxServlet
        String[] segs = part[0].split(" ");
        //{3}保存 GET 到 req. [请求方式]
        req.setMethod(segs[0]);
        //{4}保存 /XxServlet 到 req.
        req.setResPath(segs[1]);
    }

    //reqSeg[0]: 请求行
    //reqSeg[1]: 请求头
    //reqSeg[2]: 请求体(不一定有)
    public String[] splitReqStr(String allREQ) {
        String[] reqSeg = new String[3];
        //{1}分割请求头与请求体
        String[] part = allREQ.split("\r\n\r\n");

        //{2}分割请求行与请求头
        //ps: part[0] = 请求行 + 请求头
        int index = part[0].indexOf("\r\n");
        reqSeg[0] = part[0].substring(0, index);
        reqSeg[1] = part[0].substring(
                index + 2, part[0].length());

        //{3}如果存在 ---> 保存请求体。
        if (part.length == 2) {
            reqSeg[2] = part[1];
        } else {
            reqSeg[2] = "";
        }
        return reqSeg;
    }


    //{PS}从流中获取请求协议, 解析并设置相关内容到 req 对象。
    public HttpServletRequest getRequestInfo
    (InputStream is)
            throws IOException, ParseException {
        //{1}定一个缓冲区， 存放数据。
        byte[] buff = new byte[8192];
        int count = 0;
        //{2}读取数据到  buff(缓冲区)
        count = is.read(buff);
        if (count <= 0) {
            throw new ParseException("无效的Http请求。");
        }
        //{3}将字节数据解码为 String
        String reqAll = new String(buff, 0, count);
        //{4}分割 请求行[0], 请求头[1], 请求体[2]
        String[] reqSeg = splitReqStr(reqAll);
        if (reqSeg.length < 2) {
            throw new ParseException("无效的Http请求。");
        }

        //{5}去掉请求行中的 " HTTP/1.1"
        String reqLine = reqSeg[0].replace(" HTTP/1.1", "");
        String reqHead = reqSeg[1];
        String reqBody = reqSeg[2];

        //{6}创建 HttpServletRequest 对象
        HttpServletRequest req = new HttpServletRequestWapper();
        //{7}处理 "请求行"
        parseRequestLine(reqLine, req);

        //{8}处理 "请求体"
        if (reqBody != null && reqBody.length() > 0) {
            setParamsToReq(req, reqBody);
        }
        return req;  //{9}返回 req 对象..
    }

}
